
package com.shop.cloud.mall.admin.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.core.util.LocalDateTimeUtils;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.log.annotation.SysLog;
import com.shop.cloud.mall.admin.service.*;
import com.shop.cloud.mall.common.config.MallConfigProperties;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.constant.MallReturnCode;
import com.shop.cloud.mall.common.dto.PlaceOrderDTO;
import com.shop.cloud.mall.common.entity.OrderInfo;
import com.shop.cloud.mall.common.entity.ShopInfo;
import com.shop.cloud.pay.common.dto.AliBaseRequest;
import com.shop.cloud.pay.common.feign.FeignPayService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 收银台订单
 *
 * @author
 * @date 2019-09-10 15:21:22
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/ordercashier")
@Tag(description = "ordercashier", name = "收银台订单管理")
public class OrderCashierController {

    private final OrderInfoService orderInfoService;
	private final ShopInfoService shopInfoService;
	private final MallConfigProperties mallConfigProperties;
	private final FeignPayService feignPayService;


	/**
	 * 新增收银台订单
	 * @param placeOrderDTO 订单
	 * @return R
	 */
	@Operation(summary = "新增订单（收银台）")
	@PostMapping
	@PreAuthorize("@ato.hasAuthority('mall:ordercashier:add')")
	public R orderAdd(HttpServletRequest request, @RequestBody PlaceOrderDTO placeOrderDTO){
		placeOrderDTO.setDeliveryWay(MallConstants.DELIVERY_WAY_3);
		OrderInfo orderInfo = orderInfoService.orderAddCashier(request, placeOrderDTO);
		if(orderInfo == null){
			return R.failed(MallReturnCode.ERR_70003.getCode(), MallReturnCode.ERR_70003.getMsg());
		}
		return R.ok(orderInfo);
	}
	
	/**
	 * 分页查询（收银台）
	 * @param page 分页对象（收银台）
	 * @param orderInfo 收银台订单
	 * @return
	 */
	@Operation(summary = "分页查询（收银台）")
	@GetMapping("/page")
	@PreAuthorize("@ato.hasAuthority('mall:ordercashier:index')")
	public R getPage(Page page, OrderInfo orderInfo) {
		orderInfo.setDeliveryWay(MallConstants.DELIVERY_WAY_3);
		return R.ok(orderInfoService.page1(page, Wrappers.query(orderInfo)));
	}

	/**
	 * 通过id查询收银台订单
	 * @param id
	 * @return R
	 */
	@Operation(summary = "通过id查询收银台订单")
	@GetMapping("/{id}")
	@PreAuthorize("@ato.hasAuthority('mall:ordercashier:get')")
	public R getById(@PathVariable("id") String id){
		return R.ok(orderInfoService.getById1(id));
	}

	/**
	 * 取消收银台订单
	 * @param id 收银台订单
	 * @return R
	 */
	@Operation(summary = "取消收银台订单")
	@SysLog("取消收银台订单")
	@PutMapping("/cancel")
	@PreAuthorize("@ato.hasAuthority('mall:ordercashier:cancel')")
	public R orderCancel(@RequestParam(value = "id") String id){
		OrderInfo orderInfo = orderInfoService.getById(id);
		if(!MallConstants.DELIVERY_WAY_3.equals(orderInfo.getDeliveryWay())){
			return R.failed("非收银台订单");
		}
		orderInfoService.orderCancelCashier(orderInfo);
		return R.ok();
	}

	/**
	 * 通过id删除收银台订单
	 * @param id
	 * @return R
	 */
	@Operation(summary = "通过id删除收银台订单")
	@SysLog("删除收银台订单")
	@DeleteMapping("/{id}")
	@PreAuthorize("@ato.hasAuthority('mall:ordercashier:del')")
	public R removeById(@PathVariable String id){
		return R.ok(orderInfoService.removeById(id));
	}
	
	/**
	 * 统一下单接口（收银台）
	 *
	 * @param orderInfo 统一下单请求参数
	 * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
	 */
	@Operation(summary = "统一下单接口（收银台）")
	@PostMapping("/unified")
	@PreAuthorize("@ato.hasAuthority('mall:ordercashier:add')")
	public R unifiedOrder(HttpServletRequest request, @RequestBody OrderInfo orderInfo){
		String returnUrl = orderInfo.getReturnUrl();
		String quitUrl = orderInfo.getQuitUrl();
		String paymentType = orderInfo.getPaymentType();
		orderInfo = orderInfoService.getById(orderInfo.getId());
		if(orderInfo == null){
			return R.failed(MallReturnCode.ERR_70005.getCode(), MallReturnCode.ERR_70005.getMsg());
		}
		if(!CommonConstants.NO.equals(orderInfo.getIsPay())){//只有未支付的详单能发起支付
			return R.failed(MallReturnCode.ERR_70004.getCode(), MallReturnCode.ERR_70004.getMsg());
		}

		ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
		if(CommonConstants.NO.equals(shopInfo.getEnable())){
			return R.failed(MallReturnCode.ERR_80044.getCode(), MallReturnCode.ERR_80044.getMsg());
		}
		if(orderInfo.getPaymentPrice().compareTo(BigDecimal.ZERO)==0){//0元购买不调支付
			orderInfo.setPaymentTime(LocalDateTime.now());
			orderInfoService.notifyOrderCashier(orderInfo);
			return R.ok();
		}
		if(StrUtil.isBlank(paymentType)){
			return R.failed(MallReturnCode.ERR_70002.getCode(), MallReturnCode.ERR_70002.getMsg());
		}
		String body = orderInfo.getName();
		body = body.length() > 40 ? body.substring(0,39) : body;
		//微信支付
		if(MallConstants.ORDER_PAYMENT_TYPE_1.equals(paymentType)){
			//更新编号防止不同终端微信报重复订单号
			//orderInfo.setOrderNo(IdUtil.getSnowflake(0,0).nextIdStr());
			orderInfoService.updateById(orderInfo);
			WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
			wxPayUnifiedOrderRequest.setSubMchId(shopInfo.getWxMchId());
			wxPayUnifiedOrderRequest.setBody(body);
			wxPayUnifiedOrderRequest.setOutTradeNo(orderInfo.getOrderNo());
			wxPayUnifiedOrderRequest.setTotalFee(orderInfo.getPaymentPrice().multiply(new BigDecimal(100)).intValue());
			wxPayUnifiedOrderRequest.setTradeType("NATIVE");//扫码支付
			wxPayUnifiedOrderRequest.setNotifyUrl(mallConfigProperties.getNotifyHost()+MallConstants.SERVER_ROUTE_NAME_MALL+ MallConstants.ORDER_CASHIER_NOTIFY_URL_WX+"/"+orderInfo.getTenantId());
			wxPayUnifiedOrderRequest.setSpbillCreateIp(request.getRemoteAddr());
			return feignPayService.unifiedOrderWx(wxPayUnifiedOrderRequest, SecurityConstants.FROM_IN);
		}else if(MallConstants.ORDER_PAYMENT_TYPE_2.equals(paymentType)){//支付宝支付
			Map<String, Object> params = new HashMap<>();
			params.put("tradeType","QRCODE");//扫码支付
			params.put("outTradeNo",orderInfo.getOrderNo());
			params.put("totalAmount",orderInfo.getPaymentPrice().toString());
			params.put("notifyUrl",mallConfigProperties.getNotifyHost()+MallConstants.SERVER_ROUTE_NAME_MALL + MallConstants.ORDER_CASHIER_NOTIFY_URL_ALI + "/" + orderInfo.getTenantId());
			params.put("returnUrl",returnUrl);
			params.put("quitUrl",quitUrl);
			params.put("subject",body);
			AliBaseRequest aliBaseRequest = new AliBaseRequest();
			aliBaseRequest.setAppAuthToken(shopInfo.getAliAuthToken());
			aliBaseRequest.setParams(params);
			return feignPayService.unifiedOrderAli(aliBaseRequest, SecurityConstants.FROM_IN);
		}else{
			return R.failed("无此支付类型");
		}
	}

	/**
	 * 支付回调（微信）（收银台）
	 * @param xmlData
	 * @return
	 * @throws WxPayException
	 */
	@Operation(summary = "支付回调（微信）（收银台）")
	@PostMapping("/notify-wx/{tenantId}")
	public String notifyOrderWx(@RequestBody String xmlData, @PathVariable("tenantId") String tenantId) {
		log.info("支付回调（微信）:"+xmlData);
		TenantContextHolder.setTenantId(tenantId);//设置租户ID
		R<WxPayOrderNotifyResult> r = feignPayService.notifyOrderWx(xmlData, SecurityConstants.FROM_IN);
		if(r.isOk()){
			WxPayOrderNotifyResult notifyResult = r.getData();
			OrderInfo orderInfo = orderInfoService.getOne(Wrappers.<OrderInfo>lambdaQuery()
					.eq(OrderInfo::getOrderNo,notifyResult.getOutTradeNo()));
			if(orderInfo != null){
				orderInfo.setTradeType(notifyResult.getTradeType());
				if(orderInfo.getPaymentPrice().multiply(new BigDecimal(100)).intValue() == notifyResult.getTotalFee()){
					String timeEnd = notifyResult.getTimeEnd();
					LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
					orderInfo.setPaymentTime(paymentTime);
					orderInfo.setTransactionId(notifyResult.getTransactionId());
					orderInfo.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_1);
					orderInfoService.notifyOrderCashier(orderInfo);
					return WxPayNotifyResponse.success("成功");
				}else{
					return WxPayNotifyResponse.fail("付款金额与订单金额不等");
				}
			}else{
				return WxPayNotifyResponse.fail("无此订单");
			}
		}else{
			return WxPayNotifyResponse.fail(r.getMsg());
		}
	}

	/**
	 * 支付回调（支付宝）（收银台）
	 * @param request
	 * @return
	 * @throws
	 */
	@Operation(summary = "支付回调（支付宝）（收银台）")
	@ResponseBody
	@PostMapping("/notify-ali/{tenantId}")
	public String notifyOrderAli(HttpServletRequest request, @PathVariable("tenantId") String tenantId) {
		log.info("支付回调（支付宝）");
		Map<String, String> params = new HashMap<>();
		Map requestParams = request.getParameterMap();
		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			params.put(name, valueStr);
		}
		String appId = request.getParameter("app_id");
		if(StrUtil.isBlank(appId)){
			return "appId不能为空";
		}
		TenantContextHolder.setTenantId(tenantId);//设置租户ID
		OrderInfo orderInfo = orderInfoService.getOne(Wrappers.<OrderInfo>lambdaQuery()
				.eq(OrderInfo::getOrderNo,request.getParameter("out_trade_no")));
		if(orderInfo == null){
			log.error("无此订单out_trade_no："+request.getParameter("out_trade_no"));
			return "无此订单";
		}
		if(orderInfo.getPaymentPrice().compareTo(new BigDecimal(request.getParameter("total_amount"))) == 0){
			LocalDateTime paymentTime = LocalDateTimeUtils.parse(request.getParameter("gmt_payment"));
			orderInfo.setPaymentTime(paymentTime);
			orderInfo.setTransactionId(request.getParameter("trade_no"));
			orderInfo.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_2);
			orderInfoService.notifyOrderCashier(orderInfo);
			log.info("支付回调（支付宝）success");
			return "success";
		}else{
			log.error("付款金额与订单金额不等out_trade_no："+request.getParameter("out_trade_no"));
			return "付款金额与订单金额不等";
		}

	}
}
